import backtrader as bt
import logging
from datetime import datetime
from .DbOprate import DbOprate
from .TDXFunctions import TDXFunctions
from .FactorDataManager import FactorDataManager

class EMAFactorStrategy(bt.Strategy):
    """
    EMA因子策略 - 计算并存储4条基础均线到因子表
    """
    params = (
        ('n15', 15),     # 持股线周期
        ('print_log', True),  # 是否打印日志
    )
    
    def __init__(self):
        self.data_close = self.datas[0].close
        self.data_low = self.datas[0].low
        self.data_high = self.datas[0].high
        self.tdx = TDXFunctions()
        
        # 初始化因子数据管理器
        self.stock_code = self.datas[0]._name
        self.factor_manager = FactorDataManager(self.stock_code)
        
        # 确保Redis连接正常
        try:
            self.factor_manager.redis_client.ping()
            print("Redis连接成功")
        except:
            print("Redis连接失败，将只使用数据库存储")
        
        # 在初始化时加载因子数据到Redis
        loaded_count = self.factor_manager.load_factors_to_redis()
        print(f"初始化完成，加载了 {loaded_count} 条因子数据")
        # 设置日志
        self.setup_logging()
    def setup_logging(self):
        """设置日志配置"""
        self.logger = logging.getLogger(f'EMAFactorStrategy_{self.stock_code}')
        self.logger.setLevel(logging.INFO)
        
        # 创建文件处理器
        log_filename = f'ema_factor_strategy_{self.stock_code}_{datetime.now().strftime("%Y%m%d")}.log'
        file_handler = logging.FileHandler(log_filename, encoding='utf-8')
        file_handler.setLevel(logging.INFO)
        
        # 创建格式器
        formatter = logging.Formatter('%(asctime)s - %(message)s')
        file_handler.setFormatter(formatter)
        
        # 添加处理器
        if not self.logger.handlers:
            self.logger.addHandler(file_handler)
    def log_daily_factors(self, factors_dict):
        """记录每日因子到日志文件"""
        current_date = self.datas[0].datetime.date(0)
        log_msg = "\n" + "="*80 + "\n"
        log_msg += f"日期: {current_date}\n"
        log_msg += f"股票代码: {self.stock_code}\n"
        log_msg += "-"*80 + "\n"
        log_msg += f"CLOSE: {factors_dict['close']:.4f}\n"
        log_msg += f"七天线(EMA7): {factors_dict['ema7']:.4f}\n"
        log_msg += f"持股线(EMA{self.params.n15}): {factors_dict['ema15']:.4f}\n"
        log_msg += f"生命线(EMA25): {factors_dict['ema25']:.4f}\n"
        log_msg += f"初月线(EMA34): {factors_dict['ema34']:.4f}\n"
        log_msg += "="*80 + "\n"
        
        self.logger.info(log_msg)
    def save_factor_data(self, trade_date, factor_key, factor_val):
        """保存因子数据到数据库和Redis"""
        try:
            # 保存到数据库
            self.factor_manager.save_factor_to_db(trade_date, factor_key, factor_val)
            # 保存到Redis
            self.factor_manager.save_factor_to_redis(trade_date, factor_key, factor_val)
            if self.params.print_log:
                print(f"{trade_date} - 因子 {factor_key} 已保存: {factor_val:.4f}")
        except Exception as e:
            print(f"保存因子数据失败: {e}")
    def get_factor_data(self, trade_date, factor_key):
        """获取因子数据（优先从Redis获取）"""
        return self.factor_manager.get_factor_from_redis(trade_date, factor_key)
    def next(self):
        current_date = self.datas[0].datetime.date(0)
        current_price = float(self.data_close[0])
        trade_date_int = int(current_date.strftime('%Y%m%d'))
        # 检查是否已经有缓存数据
        cached_ema7 = self.get_factor_data(trade_date_int, 'EMA7')
        cached_ema15 = self.get_factor_data(trade_date_int, 'EMA15')
        cached_ema25 = self.get_factor_data(trade_date_int, 'EMA25')
        cached_ema34 = self.get_factor_data(trade_date_int, 'EMA34')
        # 如果有完整的缓存数据，使用缓存
        use_cache = all([
            cached_ema7 is not None and cached_ema7 != '',
            cached_ema15 is not None and cached_ema15 != '',
            cached_ema25 is not None and cached_ema25 != '',
            cached_ema34 is not None and cached_ema34 != ''
        ])
        
        if use_cache:
            # 使用缓存数据
            ema7_value = float(cached_ema7)
            ema15_value = float(cached_ema15)
            ema25_value = float(cached_ema25)
            ema34_value = float(cached_ema34)
            
            if self.params.print_log or len(self) <= 10:
                print(f"{current_date} - 使用缓存因子数据")
                print(f"  七天线(EMA7): {ema7_value:.4f}")
                print(f"  持股线(EMA15): {ema15_value:.4f}")
                print(f"  生命线(EMA25): {ema25_value:.4f}")
                print(f"  初月线(EMA34): {ema34_value:.4f}")
        else:
            # 重新计算因子
            if self.params.print_log or len(self) <= 10:
                print(f"{current_date} - 计算EMA因子数据...")
            
            # 计算4条EMA均线
            ema7_value = self.tdx.EMA(self.data_close, 7)
            ema15_value = self.tdx.EMA(self.data_close, self.params.n15)
            ema25_value = self.tdx.EMA(self.data_close, 25)
            ema34_value = self.tdx.EMA(self.data_close, 34)
            
            if self.params.print_log or len(self) <= 10:
                print(f"  七天线(EMA7): {ema7_value:.4f}")
                print(f"  持股线(EMA15): {ema15_value:.4f}")
                print(f"  生命线(EMA25): {ema25_value:.4f}")
                print(f"  初月线(EMA34): {ema34_value:.4f}")
            
            # 保存计算结果到数据库和Redis
            self.save_factor_data(trade_date_int, 'EMA7', ema7_value)
            self.save_factor_data(trade_date_int, 'EMA15', ema15_value)
            self.save_factor_data(trade_date_int, 'EMA25', ema25_value)
            self.save_factor_data(trade_date_int, 'EMA34', ema34_value)
        # 记录每日因子到日志
        factors_dict = {
            'close': current_price,
            'ema7': ema7_value,
            'ema15': ema15_value,
            'ema25': ema25_value,
            'ema34': ema34_value
        }
        
        # 只在前100天记录日志，避免日志文件过大
        if len(self) <= 100:
            self.log_daily_factors(factors_dict)
        
        # 实时显示（只显示前30天）
        if len(self) <= 30:
            print(f"\n{current_date} - {self.stock_code}")
            print(f"  收盘价: {current_price:.4f}")
            print(f"  EMA7: {ema7_value:.4f}")
            print(f"  EMA15: {ema15_value:.4f}")
            print(f"  EMA25: {ema25_value:.4f}")
            print(f"  EMA34: {ema34_value:.4f}")
    def stop(self):
        """策略结束时调用"""
        final_date = self.datas[0].datetime.date(0) if len(self.datas[0]) > 0 else "未知"
        self.logger.info(f"EMA因子策略运行结束 - 股票代码: {self.stock_code}, 结束日期: {final_date}")
        print(f'\n=== EMA因子策略执行完成 ===')
        print(f'股票代码: {self.stock_code}')
        print(f'日志文件: ema_factor_strategy_{self.stock_code}_*.log')
        print(f'因子数据已存储到数据库和Redis')